package cn.gzsendi.config.mybatis;

import cn.gzsendi.config.mybatis.enumn.DatabaseType;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


/**
 * @Program: mybatis_test
 * @Description: 数据源配置
 * @Author: tsh
 * @Create: 2021-01-08
 */
@Configuration
@Component
public class DynamicDataSourceConfig {

    @Bean(value = "master")
    @ConfigurationProperties(prefix = "spring.datasource.druid.master")
    public DataSource masterDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(value = "slave")
    @ConfigurationProperties(prefix = "spring.datasource.druid.slave")
    public DataSource slaveDataSource() {
        String validationQuery = "select 1";
        DruidDataSource ds = DruidDataSourceBuilder.create().build();
        ds.setInitialSize(1);//初始化数量
        ds.setMaxActive(20);//最大活跃数
        ds.setMinIdle(1);//
        ds.setMaxWait(60000);//最大等待超时时间
        ds.setValidationQuery(validationQuery);
        ds.setTestOnBorrow(false);
        ds.setTestOnReturn(false);
        ds.setTestWhileIdle(true);
        ds.setTimeBetweenEvictionRunsMillis(60000);//
        ds.setMinEvictableIdleTimeMillis(300000);//
        ds.setRemoveAbandoned(true);
        ds.setRemoveAbandonedTimeout(1800);
        ds.setLogAbandoned(true);

        //打开PSCache，并且指定每个连接PSCache的大小
        ds.setPoolPreparedStatements(false);
        ds.setMaxPoolPreparedStatementPerConnectionSize(20);

        try {
            ds.setFilters("stat");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        ds.setProxyFilters(Arrays.asList(statFilter(), logFilter(), wallFilter()));
        return ds;
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource(@Qualifier(value = "master") DataSource masterDataSource,
                                        @Qualifier(value = "slave") DataSource slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseType.master.toString(), masterDataSource);
        targetDataSources.put(DatabaseType.slave.toString(), slaveDataSource);

        return new DynamicDataSource(masterDataSource, targetDataSources);
    }

    //@Bean
    //@Primary
    public StatFilter statFilter() {
        StatFilter statFilter = new StatFilter();
        statFilter.setSlowSqlMillis(5000);//大于5秒认为是慢查询Sql
        statFilter.setLogSlowSql(true);
        statFilter.setMergeSql(true);
        return statFilter;
    }

    //@Bean
    public Slf4jLogFilter logFilter() {
        Slf4jLogFilter filter = new Slf4jLogFilter();
//        filter.setResultSetLogEnabled(false);
//        filter.setConnectionLogEnabled(false);
//        filter.setStatementParameterClearLogEnable(false);
//        filter.setStatementCreateAfterLogEnabled(false);
//        filter.setStatementCloseAfterLogEnabled(false);
//        filter.setStatementParameterSetLogEnabled(false);
//        filter.setStatementPrepareAfterLogEnabled(false);
        return filter;
    }

    private WallFilter wallFilter() {
        WallFilter wallFilter = new WallFilter();
        wallFilter.setConfig(wallConfig());
        return wallFilter;
    }


    private WallConfig wallConfig() {
        WallConfig config = new WallConfig();
        config.setMultiStatementAllow(true);//允许一次执行多条语句
        config.setNoneBaseStatementAllow(true);//允许非基本语句的其他语句
        return config;
    }
}
